#ifndef WOLF_CONSOLE_APP_HPP
#define WOLF_CONSOLE_APP_HPP

#include <vector>
#include <string>
#include "console.hpp"
#include "ConsoleMessage.hpp"
#include "common.hpp"

namespace wolf {
using namespace std;
/**
 * @brief A base class to a console application
 * @ingroup consoleMod
 *
 *
 * This class has protected methods that simules a console.
 *  Subclasse has to use only this methods and the methods
 *  returned by these methods (Not global functions or static
 *  methods (like Engine::get()) area allowed). This is necessary
 *  because it uses threads to abstract the game loop (to allow
 *  the frame idependent code) and no library functions are prepared
 *  to work with it.
 *
 **/
class WOLF_DECLSPEC ConsoleApp {
public:
	/**
	 * @brief The method call as a program.
	 *
	 * The user code goes here. Never call it directly, but instead
	 *  use call() or Console::callApp().
	 *
	 * @param The params of the app.
	 * @return An arbitrary exit code (use the c convention, 0 is ok, non-zero is not ok)
	 **/
	virtual int run(const vector<string> &params) = 0;

	/**
	 * @brief Virtual destructor
	 */
	virtual ~ConsoleApp() {
	}
protected:
	/**
	 * @brief Send a message to console queue
	 *
	 * This message must be created on heap (shouldn't be in heap)
	 *  and shouldn't be manipulated by the app after it was sent.
	 **/
	void sendMessage(ConsoleMessage *message);

	/**
	 * @brief Retrives the message
	 *
	 * If there is a message returns it. The message must to be freed by the user.
	 *  The messages are put in a queue, so you can have more than one message.
	 *  Because that we recomend use this code's piece on the frame event to check it:
	 * @code
	 *   while( (ConsoleMessage *message = receiveMessage()) != NULL)
	 *   {
	 *       switch(message->type())
	 *       {
	 *       case MESSAGE_TYPE1:
	 *           <handle type1>
	 *           break;
	 *       case MESSAGE_TYPE2:
	 *           <handle type2>
	 *           break;
	 *       default:
	 *           <error handling>
	 *       }
	 *   }
	 * @endcode
	 *
	 * @return The message or NULL if there isn't a messege.
	 **/
	ConsoleMessage *receiveMessage(void);

	/**
	 * @brief Returns the last pressed char
	 *
	 * If there is not a char, it waits to next char.
	 *  It does not show the pressed char.
	 * @see getChar()
	 **/
	int readChar(void);

	/**
	 * @brief Put the char on screen
	 *
	 *
	 **/
	void putChar(int c);

	/**
	 * @brief Returns if it has a char on queue
	 *
	 *
	 **/
	bool hasChar(void);

	/**
	 * @brief Clear screen
	 *
	 *
	 **/
	void clear(void);

	/**
	 * @brief Sets the cursor's color
	 *
	 *
	 **/
	void setColor(const Color &color);

	/**
	 * @brief Gets the cursor's color
	 *
	 *
	 **/
	const Color getColor(void);

	/**
	 * @brief Gets the cursor position
	 *
	 *
	 **/
	void getXY(int &x, int &y);

	/**
	 * @brief Changes the cursor's position
	 *
	 *
	 **/
	void gotoXY(int x, int y);

	/**
	 * @brief Puts a string on screen
	 *
	 *
	 **/
	inline void putString(const char *s) {
		for (const char *c = s; *c != 0; ++c)
			putChar(*c);
	}

	/**
	 * @brief Puts a string on screen
	 *
	 *
	 **/
	inline void putString(const string &s) {
		putString(s.c_str());
	}

	/**
	 * @brief Gets a Char
	 *
	 * Works similar to readChar(), but ir shows the character on screen
	 **/
	inline int getChar(void) {
		int c;
		putChar(c = readChar());
		return c;
	}

	/**
	 * @brief Gets a entire line from input
	 *
	 *
	 **/
	string getLine(void);

	/**
	 * @brief Gets the next 'word'
	 *
	 * basicly it delimits the string by spaces and endlines
	 **/
	inline string getString() {
		string result;
		int c = getChar();
		while (c != '\n' && c != -1 && c != ' ' && c != '\t') {
			result += c;
			c = getChar();
		}
		return result;
	}

	/**
	 * @brief Calls another app
	 *
	 * It stops the current until the another is exited.
	 **/
	int call(ConsoleApp &app, const vector<string> &params);
private:
	Console *console;

	friend class Console;
};
}

#endif // WOLF_CONSOLE_APP_HPP
